package com.googlecode.totallylazy.parser;

import com.googlecode.totallylazy.Segment;
import com.googlecode.totallylazy.Sequence;

import static com.googlecode.totallylazy.Sequences.sequence;

public class OrParser<A> extends Parser<A> {
    private final Sequence<Parse<A>> parsers;

    private OrParser(Iterable<? extends Parse<? extends A>> parses) {
        this.parsers = sequence(parses).unsafeCast();
    }

    public static <A> OrParser<A> or(Parse<? extends A> parserA, Parse<? extends A> parserB) {
        return or(sequence(parserA, parserB));
    }

    public static <A> OrParser<A> or(Parse<? extends A> parserA, Parse<? extends A> parserB, final Parse<? extends A> parserC) {
        return or(sequence(parserA, parserB, parserC));
    }

    public static <A> OrParser<A> or(Parse<? extends A> parserA, Parse<? extends A> parserB, final Parse<? extends A> parserC, final Parse<? extends A> parserD) {
        return or(sequence(parserA, parserB, parserC, parserD));
    }

    public static <A> OrParser<A> or(Parse<? extends A> parserA, Parse<? extends A> parserB, final Parse<? extends A> parserC, final Parse<? extends A> parserD, final Parse<? extends A> parserE) {
        return or(sequence(parserA, parserB, parserC, parserD, parserE));
    }

    public static <A> OrParser<A> or(Parse<? extends A>... parsers) {
        return or(sequence(parsers));
    }

    public static <A> OrParser<A> or(Iterable<? extends Parse<? extends A>> parsers) {
        return new OrParser<A>(parsers);
    }


    @Override
    public String toString() {
        return parsers.toString(" or ");
    }

    @Override
    public Result<A> parse(Segment<Character> characters) throws Exception {
        Result<A> result = null;
        for (Parse<A> parser : parsers) {
            result = parser.parse(characters);
            if (result instanceof Success) return result;
        }
        return result;
    }
}
